using System;
using System.Collections.Generic;
using System.Text;
using FireStarter.Base;
using FireStarter.CodeGeneration;
using FireStarter.CodeGeneration.Generator;
using FireStarter.CodeGeneration.Parser;
using FireStarterModeller.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using NUnit.Framework;

namespace FireStarter.Test.CodeGeneration.Generation
{
    [TestFixture]
    public class TestGenerationIntegration : TestBase
    {
        [Test]
        public void Test_Simple()
        {
            //---------------Set up test pack-------------------
            const string template = @"
                using System;
                using Habanero.BO;

                namespace <<|=ClassNameBO|>>
                {
                    public partial class <<|=ClassNameBO|>> : BusinessObject
                    {
                    }
                }
                ";
            string templateCopy = template;
            StatementParser statementParser = new StatementParser();
            IModelClass dmClass = new DMClass();
            dmClass.ClassName = TestUtilsCodeGen.GetRandomString();
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), new ReflectionGenerationStrategy());
            string expected = template;
            expected = expected.Replace("<<|=ClassNameBO|>>", dmClass.ClassName);
            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            TemplateExpression templateExpression = statementParser.Parse(ref templateCopy, new List<IActionParser> { new ValueExpressionParser() });
            string generatedTemplate = templateExpression.Generate(modelStrategyMapper, dmClass);
            //---------------Test Result -----------------------
            Assert.AreEqual("", templateCopy);
            Assert.AreEqual(expected, generatedTemplate);
        }

        [Test]
        public void Test_ValueModifiers()
        {
            //---------------Set up test pack-------------------
            const string template = @"
                using System;
                using <<|=ClassNameBO+|>>;

                namespace <<|=#ClassNameBO+|>>
                {
                    public partial class <<|=#ClassNameBO|>> : BusinessObject
                    {
                    }
                }
                ";
            string templateCopy = template;
            StatementParser statementParser = new StatementParser();
            IModelClass dmClass = new DMClass();
            dmClass.ClassName = "Class";
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), new ReflectionGenerationStrategy());
            string expected = template;
            expected = expected.Replace("<<|=ClassNameBO+|>>", "Classes");
            expected = expected.Replace("<<|=#ClassNameBO+|>>", "classes");
            expected = expected.Replace("<<|=#ClassNameBO|>>", "class");
            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            TemplateExpression templateExpression = statementParser.Parse(ref templateCopy, new List<IActionParser> { new ValueExpressionParser() });
            string generatedTemplate = templateExpression.Generate(modelStrategyMapper, dmClass);
            //---------------Test Result -----------------------
            Assert.AreEqual("", templateCopy);
            Assert.AreEqual(expected, generatedTemplate);
        }

        [Test]
        public void Test_ForEach()
        {
            //---------------Set up test pack-------------------
            const string template = @"
                using System;
                using Habanero.BO;

                namespace <<|=ClassNameBO|>>
                {
                    public partial class <<|=ClassNameBO|>> : BusinessObject
                    {
                        <<|FOREACH(Properties):
                        public string <<|=PropertyName|>>
                        {
                            get { return GetPropertyValue(""<<|=PropertyName|>>""); }
                        }
                        |>>
                    }
                }
                ";
            string templateCopy = template;
            StatementParser statementParser = new StatementParser();
            IModelClass dmClass = new DMClass();
            dmClass.ClassName = TestUtilsCodeGen.GetRandomString();
            IModelProperty modelProperty = new DMProperty();
            modelProperty.PropertyName = TestUtilsCodeGen.GetRandomString();
            ((DMProperty) modelProperty).Class = (DMClass) dmClass;
            dmClass.Properties.Add(modelProperty);
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), new ReflectionGenerationStrategy());
            string expected = template;
            expected = expected.Replace("<<|=ClassNameBO|>>", dmClass.ClassName);
            expected = expected.Replace("                        <<|FOREACH(Properties):" + Environment.NewLine, "");
            expected = expected.Replace("<<|=PropertyName|>>", modelProperty.PropertyName);
            expected = expected.Replace(@"                        |>>" + Environment.NewLine, "");
            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            TemplateExpression templateExpression = statementParser.Parse(ref templateCopy);
            string generatedTemplate = templateExpression.Generate(modelStrategyMapper, dmClass);
            //---------------Test Result -----------------------
            Assert.AreEqual("", templateCopy);
            Assert.AreEqual(expected, generatedTemplate);
        }

        [Test]
        public void Test_ForEach_WithIf_True()
        {
            //---------------Set up test pack-------------------
            const string template = @"
                using System;
                using Habanero.BO;

                namespace <<|=ClassNameBO|>>
                {
                    public partial class <<|=ClassNameBO|>> : BusinessObject
                    {
                        <<|FOREACH(Properties):
                        public string <<|=PropertyName|>>
                        {
                            get { return GetPropertyValue(""<<|=PropertyName|>>""); }
<<|IF(HasSetter):                            set { SetPropertyValue(""<<|=PropertyName|>>"", value); }
|>>                        }
                        |>>
                    }
                }
                ";
            string templateCopy = template;
            StatementParser statementParser = new StatementParser();
            IModelClass dmClass = new DMClass();
            dmClass.ClassName = TestUtilsCodeGen.GetRandomString();
            IModelProperty modelProperty = new DMProperty();
            modelProperty.PropertyName = TestUtilsCodeGen.GetRandomString();
            ((DMProperty)modelProperty).Class = (DMClass)dmClass;
            modelProperty.HasSetter = true;
            dmClass.Properties.Add(modelProperty);
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), new ReflectionGenerationStrategy());
            string expected = template;
            expected = expected.Replace("<<|=ClassNameBO|>>", dmClass.ClassName);
            expected = expected.Replace("                        <<|FOREACH(Properties):" + Environment.NewLine, "");
            expected = expected.Replace("<<|=PropertyName|>>", modelProperty.PropertyName);
            expected = expected.Replace("<<|IF(HasSetter):", "");
            expected = expected.Replace(@"                        |>>" + Environment.NewLine, "");
            expected = expected.Replace(@"|>>", "");
            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            TemplateExpression templateExpression = statementParser.Parse(ref templateCopy);
            string generatedTemplate = templateExpression.Generate(modelStrategyMapper, dmClass);
            //---------------Test Result -----------------------
            Assert.AreEqual("", templateCopy);
            Assert.AreEqual(expected, generatedTemplate);
        }

        [Test]
        public void Test_ForEach_WithIf_False()
        {
            //---------------Set up test pack-------------------
            const string template = @"
                using System;
                using Habanero.BO;

                namespace <<|=ClassNameBO|>>
                {
                    public partial class <<|=ClassNameBO|>> : BusinessObject
                    {
                        <<|FOREACH(Properties):
                        public string <<|=PropertyName|>>
                        {
                            get { return GetPropertyValue(""<<|=PropertyName|>>""); }
<<|IF(HasSetter):                            set { SetPropertyValue(""<<|=PropertyName|>>"", value); }
|>>                        }
                        |>>
                    }
                }
                ";
            string templateCopy = template;
            StatementParser statementParser = new StatementParser();
            IModelClass dmClass = new DMClass();
            dmClass.ClassName = TestUtilsCodeGen.GetRandomString();
            IModelProperty modelProperty = new DMProperty {PropertyName = TestUtilsCodeGen.GetRandomString()};
            ((DMProperty)modelProperty).Class = (DMClass)dmClass;
            modelProperty.HasSetter = false;
            dmClass.Properties.Add(modelProperty);
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), new ReflectionGenerationStrategy());
            string expected = template;
            expected = expected.Replace("<<|=ClassNameBO|>>", dmClass.ClassName);
            expected = expected.Replace("                        <<|FOREACH(Properties):" + Environment.NewLine, "");
            expected = expected.Replace(@"set { SetPropertyValue(""<<|=PropertyName|>>"", value); }" + Environment.NewLine, "");
            expected = expected.Replace("<<|=PropertyName|>>", modelProperty.PropertyName);
            expected = expected.Replace("<<|IF(HasSetter):                            ", "");
            expected = expected.Replace(@"                        |>>" + Environment.NewLine, "");
            expected = expected.Replace("|>>", "");
            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            TemplateExpression templateExpression = statementParser.Parse(ref templateCopy);
            string generatedTemplate = templateExpression.Generate(modelStrategyMapper, dmClass);
            //---------------Test Result -----------------------
            Assert.AreEqual("", templateCopy);
            Assert.AreEqual(expected, generatedTemplate);
        }

        [Test]
        public void Test_If()
        {
            //---------------Set up test pack-------------------
            const string template = @"
                <<|IF(ISCOMPULSORY):<<|=DEFAULTVALUE|>>|>>
                <<|IF(!ISCOMPULSORY):null|>>
                ";
            string templateCopy = template;
            StatementParser statementParser = new StatementParser();
            DMProperty modelProperty = new DMProperty {DefaultValue = "hello", Compulsory = true};
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), new ReflectionGenerationStrategy());
            string expected = template;
            expected = expected.Replace("<<|IF(ISCOMPULSORY):<<|=DEFAULTVALUE|>>|>>", "hello");
            expected = expected.Replace("                <<|IF(!ISCOMPULSORY):null|>>" + Environment.NewLine, "");
            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            TemplateExpression templateExpression = statementParser.Parse(ref templateCopy);
            string generatedTemplate = templateExpression.Generate(modelStrategyMapper, modelProperty);
            //---------------Test Result -----------------------
            Assert.AreEqual("", templateCopy);
            Assert.AreEqual(expected, generatedTemplate);
        }

        [Test]
        public void Test_ExtraNewLinesRemoved()
        {
            //---------------Set up test pack-------------------
            const string template = @"
                <<|=CLASSNAMEBO|>><<|-- comment --|>>
                <<|-- comment --|>>
                <<|IF(!PrimaryKeyIsID):
                <<|=CLASSNAMEBO|>>1
                |>>
                <<|IF(PrimaryKeyIsID):
                <<|=CLASSNAMEBO|>>2
                |>>
                <<|IF(PrimaryKeyIsID):<<|=CLASSNAMEBO|>>2|>>
                <<|FOREACH(Properties):
                <<|=PROPERTYNAME|>>
                |>>
                <<|FOREACH(Properties):<<|=PROPERTYNAME|>>|>>
                <<|-- comment --|>><<|-- comment --|>>
                <<|-- comment --|>><<|=CLASSNAMEBO|>>3<<|-- comment --|>>
                text
";
            const string expected = @"
                Class
                Class2
                Class2
                Prop1
                Prop2
                Prop1Prop2
                Class3
                text
";
            string templateCopy = template;
            StatementParser statementParser = new StatementParser();

            IModelClass dmClass = TestUtilsCodeGen.CreateModelClass("Class");
            ((DMClass) dmClass).ObjectIdentity = new DMObjectIdentity();
            ((DMClass)dmClass).ObjectIdentity.IsObjectID = true;
            var propertyOnClass = TestUtilsCodeGen.CreatePropertyOnClass((DMClass)dmClass, "Prop1");
            TestUtilsCodeGen.CreatePropertyOnClass((DMClass)dmClass, "Prop2");
            ((DMClass)dmClass).ObjectIdentity.Properties.Add(propertyOnClass);
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), new ReflectionGenerationStrategy());
            //-------------Assert Preconditions -------------
//            Assert.IsTrue(((DMClass)dmClass).ObjectIdentity.);
            //---------------Execute Test ----------------------
            ((DMClass)dmClass).Properties.Sort("PropertyName", true, true);
            TemplateExpression templateExpression = statementParser.Parse(ref templateCopy);
            string generatedTemplate = templateExpression.Generate(modelStrategyMapper, dmClass);
            //---------------Test Result -----------------------
            Assert.AreEqual("", templateCopy);
            Assert.AreEqual(expected, generatedTemplate);
        }
    }
}
